//
// Created by test on 23-3-15.
//

#ifndef LINUX_HEAP_TIMER_H
#define LINUX_HEAP_TIMER_H
//
// Created by test on 23-3-13.
//
#include<time.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<unistd.h>
#include<stdlib.h>
#include<assert.h>
#include<string.h>
#include<stdio.h>
#include<pthread.h>
#include<sys/epoll.h>
#include<fcntl.h>
#include<errno.h>
#include<exception>
#include"http_conn.h"
#define BUF_SIZE 64
class heap_timer;
struct client_data{
    http_conn info;
    heap_timer* timer;
};
class heap_timer{
public:
    time_t expire;
    void (*cb_func)(client_data*);
    client_data* user_data;
    heap_timer(){
        expire=time(NULL);
    }
    heap_timer(int delay){
        expire=time(NULL)+delay;
    }
};
class time_heap{
private:
    heap_timer** array;
    int capacity;
    int cur_size;
public:
    time_heap(int cap) :capacity(cap),cur_size(0){
        array=new heap_timer*[capacity];
        if(!array){
            throw std::exception();
        }
        for(int i=0;i<capacity;i++){
            array[i]=NULL;
        }
    }
    time_heap(heap_timer** init_array,int size,int capacity):cur_size(size),capacity(capacity){
        if(capacity<size){
            throw std::exception();
        }
        array=new heap_timer* [capacity];
        if(!array){
            throw std::exception();
        }
        for(int i=0;i<capacity;i++){
            array[i]=NULL;
        }
        if(size!=0){
            for(int i=0;i<size;i++){
                array[i]=init_array[i];
            }
            for(int i=(cur_size-1)/2;i>=0;i--){
                percolate_down(i);
            }
        }
    }
    ~time_heap(){
        for(int i=0;i<cur_size;i++){
            delete array[i];
        }
        delete [] array;
    }
    void add_timer(heap_timer* timer) {
        if(!timer){
            return;
        }
        if(cur_size>=capacity) {
            resize();
        }
        int hole=cur_size++;
        int parent=0;
        for(;hole>0;hole=parent){
            parent=(hole-1)/2;
            if(array[parent]->expire<=timer->expire){
                break;
            }
            array[hole]=array[parent];
        }
        array[hole]=timer;
    }
    void del_timer(heap_timer* timer){
        if(!timer){
            return;
        }
        timer->cb_func=NULL;
    }
    heap_timer* top() const{
        if(empty()){
            return NULL;
        }
        return array[0];
    }
    void pop_timer(){
        if(empty()){
            return;
        }
        if(array[0]){
            delete array[0];
            array[0]=array[--cur_size];
            percolate_down(0);
        }
    }
    void tick(){
        heap_timer* tmp=array[0];
        time_t cur=time(NULL);
        while(!empty()){
            if(!tmp){
                break;
            }
            if(tmp->expire>cur){
                break;
            }
            if(array[0]->cb_func){
                array[0]->cb_func(array[0]->user_data);
            }
            pop_timer();
            tmp=array[0];
        }
    }
    bool empty() const {
        return cur_size==0;
    }
private:
    void percolate_down(int hole){
        heap_timer* tmp=array[hole];
        int child=0;
        for(;(hole*2+1)<=(cur_size-1);hole=child){
            child=hole*2+1;
            if(array[hole]->expire>array[child]->expire&&child<(cur_size+1)){
                child++;
            }
            if(array[hole]->expire<array[child]->expire){
                array[hole]=array[child];
            }
            else{
                break;
            }
        }
        array[child]=tmp;
    }
    void resize() {
        heap_timer** temp=new heap_timer* [capacity*2];
        for(int i=0;i<capacity*2;i++){
            temp[i]=NULL;
        }
        if(!temp){
            throw std::exception();
        }
        capacity=2*capacity;
        for(int i=0;i<cur_size;i++){
            temp[i]=array[i];
        }
        delete [] array;
        array=temp;
    }
};
#endif //LINUX_HEAP_TIMER_H
